import com.deepoove.poi.XWPFTemplate;
import org.apache.poi.xwpf.usermodel.*;
import org.apache.xmlbeans.XmlException;
import org.openxmlformats.schemas.wordprocessingml.x2006.main.CTRow;
import org.springframework.util.StringUtils;

import java.io.*;
import java.util.List;
import java.util.Map;

/**
 * 通过word模板生成新的word工具类
 * 模板汇总使用{{value_xxxx}}做标记
 *
 * 使用
 * String templateFilepath="template.docx"
 * String newFilepath = "newfile.docx"
 * InputStream is = new FileInputStream(templateFilepath);
 * XWPFDocument document = new XWPFDocument(is);
 * WordUtil.replaceParagraphInDocument(document,map);
 * WordUtil.replaceTableInDocument(document,map);
 * OutputStream os = new FileOutputStream(newFilepath);
 * document.write(os);
 * os.close();
 * is.close();
 *
 */
public class WordUtil {

    private static final String DATA_PLACE_FLAG = "{{value_";
    private static final String DATA_PLACE_FLAG_START = "{{";
    private static final String DATA_PLACE_FLAG_END = "}}";
    private static final String DATA_PLACE_FLAG_START_SINGLE = "{";
    private static final String DATA_PLACE_FLAG_END_SINGLE = "}";

    /**
     * 段落中替换文本
     * 段落中插入文本
     * 表格中替换行
     * 变更中插入行
     * 最小单位处理
     * @param xwpfParagraph
     * @param map
     */
    public static void replaceInParagraph(XWPFParagraph xwpfParagraph, Map<String,String> map){
        String text = xwpfParagraph.getText();
//        System.out.println(String.format("xwpfParagraph\ttext\t[%s]",text));
        if(text.contains(DATA_PLACE_FLAG)){
            List<XWPFRun> xwpfRuns = xwpfParagraph.getRuns();
            StringBuilder tempStringBuilder = new StringBuilder();
            boolean isBeginFlag = false;
            boolean isEndFlag = false;
            boolean beginFinish = false;
            boolean endFinish = false;
            for(XWPFRun xwpfRun:xwpfRuns){
                String currentText = xwpfRun.text();
//                System.out.println(String.format("xwpfRun\t[%s]",currentText));
                int begin_pos = 0;
                int end_pos = 0;
                if(currentText.contains(DATA_PLACE_FLAG_START_SINGLE)||currentText.contains(DATA_PLACE_FLAG_END_SINGLE)){
                    if(currentText.contains(DATA_PLACE_FLAG_START)){
                        begin_pos = currentText.indexOf(DATA_PLACE_FLAG_START);
                        tempStringBuilder = new StringBuilder();
                        tempStringBuilder.append(currentText.substring(begin_pos));
                        xwpfRun.setText("",begin_pos);
                        begin_pos = 0;
                        isBeginFlag = true;
                        beginFinish = true;
                        isEndFlag = false;
                    } else if(currentText.contains(DATA_PLACE_FLAG_START_SINGLE)){
                        if(currentText.length()==1){
                            if(isBeginFlag){
                                beginFinish = true;
                            } else {
                                isBeginFlag = true;
                                isEndFlag = false;
                                tempStringBuilder = new StringBuilder();
                                tempStringBuilder.append(currentText);
                                xwpfRun.setText("",0);
                                beginFinish = false;
                            }
                        } else {
                            if(isBeginFlag){
                                if(currentText.startsWith(DATA_PLACE_FLAG_START_SINGLE)){
                                    tempStringBuilder.append(currentText);
                                    beginFinish = true;
                                } else {
                                    tempStringBuilder = new StringBuilder();
                                    tempStringBuilder.append(currentText.substring(currentText.indexOf(DATA_PLACE_FLAG_START_SINGLE)));
                                }
                            } else {
                                isBeginFlag = true;
                                isEndFlag = false;
                                tempStringBuilder = new StringBuilder();
                                tempStringBuilder.append(currentText.substring(currentText.indexOf(DATA_PLACE_FLAG_START_SINGLE)));
                            }
                            xwpfRun.setText("",currentText.indexOf(DATA_PLACE_FLAG_START_SINGLE));
                        }
                    }
                    if(isBeginFlag){
                        if(currentText.contains(DATA_PLACE_FLAG_END)){
                            end_pos = currentText.indexOf(DATA_PLACE_FLAG_END)+2;
                            tempStringBuilder.append(currentText, begin_pos, end_pos);
//                            System.out.println(String.format("tempStringBuilder\t[%s]",tempStringBuilder));
                            String flagString = tempStringBuilder.toString();
                            String key = flagString.substring(flagString.indexOf(DATA_PLACE_FLAG_START)+2,flagString.indexOf(DATA_PLACE_FLAG_END));
                            String newValue = map.get(key);
                            newValue = StringUtils.hasLength(newValue)&&(!"null".equalsIgnoreCase(newValue))?newValue:"";
                            xwpfRun.setText(newValue,0);
                            isBeginFlag = false;
                        } else if(currentText.contains(DATA_PLACE_FLAG_END_SINGLE)){
                            if(currentText.length()==1){
                                if(isEndFlag){
                                    endFinish = true;
                                    tempStringBuilder.append(currentText);
//                                    System.out.println(String.format("tempStringBuilder\t[%s]",tempStringBuilder));
                                    String flagString = tempStringBuilder.toString();
                                    String key = flagString.substring(flagString.indexOf(DATA_PLACE_FLAG_START)+2,flagString.indexOf(DATA_PLACE_FLAG_END));
                                    String newValue = map.get(key);
                                    newValue = StringUtils.hasLength(newValue)&&(!"null".equalsIgnoreCase(newValue))?newValue:"";
                                    xwpfRun.setText(newValue,0);
                                    isBeginFlag = false;
                                } else {
                                    isEndFlag = true;
                                    if(!beginFinish){
                                        tempStringBuilder.append(currentText);
                                    }
                                }
                            } else {
                                tempStringBuilder.append(currentText, 0, currentText.indexOf(DATA_PLACE_FLAG_END_SINGLE)+1);
                                xwpfRun.setText("",0);
                                if(isEndFlag){
                                    if(currentText.startsWith(DATA_PLACE_FLAG_END_SINGLE)){
//                                        System.out.println(String.format("tempStringBuilder\t[%s]",tempStringBuilder));
                                        String flagString = tempStringBuilder.toString();
                                        String key = flagString.substring(flagString.indexOf(DATA_PLACE_FLAG_START)+2,flagString.indexOf(DATA_PLACE_FLAG_END));
                                        String newValue = map.get(key);
                                        newValue = StringUtils.hasLength(newValue)&&(!"null".equalsIgnoreCase(newValue))?newValue:"";
                                        xwpfRun.setText(newValue,0);
                                        endFinish = true;
                                        isBeginFlag = false;
                                    } else {
                                    }
                                } else {
                                    isEndFlag = true;
                                }
                            }
                        }
                    }
                } else {
                    if(isBeginFlag){
                        tempStringBuilder.append(currentText);
                        if(!beginFinish){
                            xwpfRun.setText(tempStringBuilder.toString(),0);
                            isBeginFlag = false;
                        } else {
                            xwpfRun.setText("",0);
                        }
                    }
                }
            }
        }
    }

    /**
     * 替换单元格内容
     * @param xwpfTableCell
     * @param map
     */
    public static void replaceInCell(XWPFTableCell xwpfTableCell, Map<String,String> map){
        List<XWPFParagraph> xwpfParagraphs = xwpfTableCell.getParagraphs();
        for(XWPFParagraph xwpfParagraph:xwpfParagraphs){
            replaceInParagraph(xwpfParagraph,map);
        }
    }

    /**
     * 替换表格中的行
     * @param xwpfTableRow
     * @param map
     */
    public static void replaceInTableRow(XWPFTableRow xwpfTableRow, Map<String,String> map){
        List<XWPFTableCell> xwpfTableCells = xwpfTableRow.getTableCells();
        for(XWPFTableCell xwpfTableCell:xwpfTableCells){
            replaceInCell(xwpfTableCell,map);
        }
    }

    /**
     * 替换表格内指定行
     * @param xwpfTable
     * @param map
     * @param rowIndex
     */
    public static void replaceTableRowInTableWithRowIndex(XWPFTable xwpfTable, Map<String,String> map,int rowIndex){
        XWPFTableRow xwpfTableRow = xwpfTable.getRows().get(rowIndex);
        replaceInTableRow(xwpfTableRow,map);
    }

    /**
     * 替换表格中内容
     * @param xwpfTable
     * @param map
     */
    public static void replaceInTable(XWPFTable xwpfTable, Map<String,String> map){
        List<XWPFTableRow> xwpfTableRows = xwpfTable.getRows();
        for(XWPFTableRow xwpfTableRow:xwpfTableRows){
            replaceInTableRow(xwpfTableRow,map);
        }
    }

    /**
     * 复制表格中的多行，并替换数据
     * @param xwpfTable
     * @param srcBeginIndex
     * @param srcEndIndex
     * @param listData
     */
    public static void insertRowsAndFillData(XWPFTable xwpfTable,int srcBeginIndex,int srcEndIndex,List listData){
        try {
            int dataSize = listData.size();
            int dataRowLength = srcEndIndex-srcBeginIndex+1;
            List<XWPFTableRow> xwpfTableRows = xwpfTable.getRows();
//        for(XWPFTableRow xwpfTableRow:xwpfTableRows){
            int tableRowSize = xwpfTableRows.size();
            for(int i=0;i<tableRowSize;i++){
                XWPFTableRow xwpfTableRow = xwpfTableRows.get(i);
                if(i>=srcBeginIndex&&i<=srcEndIndex){
                    for(int m=0;m<dataSize-1;m++){
                        Map<String,String> valueMap = (Map<String, String>) listData.get(m+1);
                        CTRow ctRow = CTRow.Factory.parse(xwpfTableRow.getCtRow().newInputStream());//重点行
                        XWPFTableRow newRow = new XWPFTableRow(ctRow,xwpfTable);
                        List<XWPFTableCell> xwpfTableCells = xwpfTableRow.getTableCells();
                        List<XWPFTableCell> newCells = newRow.getTableCells();
                        int cellSize = xwpfTableCells.size();
                        for(int k=0;k<cellSize;k++){
                            XWPFTableCell xwpfTableCell = xwpfTableCells.get(k);
                            XWPFTableCell newCell = newCells.get(k);
                            for(int p=0;p<xwpfTableCell.getParagraphs().size();p++){
                                XWPFParagraph xwpfParagraph = xwpfTableCell.getParagraphs().get(p);
                                XWPFParagraph newParagraph = newCell.getParagraphs().get(p);
                                replaceInParagraph(newParagraph,valueMap);
                            }
                        }
                        int newRowNum = (i-srcBeginIndex)+(i-srcBeginIndex)*m+(srcEndIndex+1)+m;
                        xwpfTable.addRow(newRow,newRowNum);
                    }
                }
            }
            xwpfTableRows = xwpfTable.getRows();
            for(int m=0;m<1;m++){
                Map<String,String> valueMap = (Map<String, String>) listData.get(m);
                int rowBeginIndex = srcBeginIndex+dataRowLength*m;
                int rowEndIndex = rowBeginIndex+dataRowLength;
                for(int n=rowBeginIndex;n<rowEndIndex;n++){
                    XWPFTableRow xwpfTableRow = xwpfTableRows.get(n);
                    List<XWPFTableCell> xwpfTableCells = xwpfTableRow.getTableCells();
                    for(XWPFTableCell xwpfTableCell:xwpfTableCells){
                        List<XWPFParagraph> paragraphs = xwpfTableCell.getParagraphs();
                        for(int p=0;p<paragraphs.size();p++) {
                            XWPFParagraph xwpfParagraph = paragraphs.get(p);
                            replaceInParagraph(xwpfParagraph,valueMap);
                        }
                    }
                }
            }
        } catch (XmlException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    /**
     * 替换文件中的指定段落
     * @param document
     * @param map
     * @param paragraphIndex
     */
    public static void replaceParagraphInDocumentWithParagraphIndex(XWPFDocument document, Map<String,String> map,int paragraphIndex){
        XWPFParagraph xwpfParagraph = document.getParagraphs().get(paragraphIndex);
        replaceInParagraph(xwpfParagraph,map);
    }

    /**
     * 替换文件中的指定表格
     * @param document
     * @param map
     * @param tableIndex
     */
    public static void replaceInTableInDocumentWithTableIndex(XWPFDocument document,Map<String,String> map,int tableIndex){
        XWPFTable xwpfTable = document.getTables().get(tableIndex);
        replaceInTable(xwpfTable,map);
    }

    public static void insertMultiRowsInDocumentWithTableIndex(XWPFDocument document, List listData, int tableIndex, int srcBeginIndex, int srcEndIndex){
        insertRowsAndFillData(document.getTables().get(tableIndex),srcBeginIndex,srcEndIndex,listData);
    }

    public static void replaceParagraphInDocument(XWPFDocument document,Map<String,String> map){
        for(XWPFParagraph xwpfParagraph:document.getParagraphs()){
            replaceInParagraph(xwpfParagraph,map);
        }
    }

    public static void replaceTableInDocument(XWPFDocument document,Map<String,String> map){
        for(XWPFTable xwpfTable:document.getTables()){
            replaceInTable(xwpfTable,map);
        }
    }
    
    public static void replaceTableRowInDocumentWithRowIndex(XWPFDocument document,Map<String,String> map,int tableIndex,int rowIndex){
        replaceInTableRow(document.getTables().get(tableIndex).getRows().get(rowIndex),map);
    }

    public static void replaceAllInDocument(XWPFDocument document,Map<String,String> map){
        replaceParagraphInDocument(document,map);
        replaceTableInDocument(document,map);
    }

    public static void main(String[] args) {

    }
}
